// 将数据和节点挂载在一起
function Compile(el, vm){
  // el表示替换的范围
  vm.$el = document.querySelector(el);

  // 这里注意我们没有去直接操作DOM，而是把这个步骤移到内存中来操作，这里的操作是不会引发DOM节点的回流
  // 详情请看：https://developer.mozilla.org/zh-CN/docs/Web/API/Document/createDocumentFragment
  let fragment = document.createDocumentFragment(); // 文档碎片,
  let child;

  while (child = vm.$el.firstChild) {
    // 将app的内容移入内存中
    fragment.appendChild(child);
  }
  /* 如下注释：
  <div id="app">
    <div>
      <div>对象数据(a.b)：<span style="color: rgb(170, 18, 18)">{{a.b}}</span></div>
      <div>对象数据(c)：<span style="color: rgb(9, 187, 211);">{{c}}</span></div>
    </div>
    <input type="text" v-model="a.b" value="">
  </div>
  */

  replace(fragment);
  function replace (fragment) {
    Array.from(fragment.childNodes).forEach(node => { // 循环每一层
      let text = node.textContent;
      let reg = /\{\{(.*)\}\}/g;
      // 这里做了判断只有文本节点才去匹配，而且还要带{{***}}的字符串,文本节点为3
      if (node.nodeType === 3 && reg.test(text)) {
        // 把匹配到的内容拆分成数组
        let arr = RegExp.$1.split('.'); 
        let val = vm;

        // 这里对我们匹配到的定义数组，会依次去遍历它，来实现对实例的深度赋值
        arr.forEach(function (k) { // this.a.b  this.c
          val = val[k]
        })

        // 在这里运用了Watcher函数来新增要操作的事情
        new Watcher(vm, RegExp.$1, function (newVal) {
          node.textContent = text.replace(/\{\{(.*)\}\}/, newVal)
        })

        // 用字符串的replace方法替换掉我们获取到的数据val
        node.textContent = text.replace(/\{\{(.*)\}\}/, val);
      }

      // 这里做了判断，如果有子节点的话 使用递归
      if (node.childNodes) {
        replace(node)
      }
    })
  }

  // 最后把编译完的DOM加入到app元素中
  vm.$el.appendChild(fragment)

}